#include "stm32f10x.h"
#include "H_I2C.h"

/**
  * @brief  初始化硬件I2C
  * @param  hI2C: I2C配置结构体指针
  * @retval 无
  */
void H_I2C_Init(H_I2C_InitTypeDef* hI2C)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef I2C_InitStructure;
    
    // 开启GPIO和I2C外设时钟
    if (hI2C->I2Cx == I2C1)
    {
        // I2C1: SCL-PB6, SDA-PB7
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
        
        // 配置GPIO引脚
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;  // 复用开漏输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
    }
    else if (hI2C->I2Cx == I2C2)
    {
        // I2C2: SCL-PB10, SDA-PB11
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
        
        // 配置GPIO引脚
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;  // 复用开漏输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
    }
    
    // 复位I2C外设
    I2C_DeInit(hI2C->I2Cx);
    
    // 配置I2C外设
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = hI2C->OwnAddress;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = hI2C->AcknowledgedAddress;
    I2C_InitStructure.I2C_ClockSpeed = hI2C->ClockSpeed;
    
    // 初始化I2C外设
    I2C_Init(hI2C->I2Cx, &I2C_InitStructure);
    
    // 使能I2C外设
    I2C_Cmd(hI2C->I2Cx, ENABLE);
}

/**
  * @brief  产生I2C起始信号
  * @param  I2Cx: 要操作的I2C外设
  * @retval 无
  */
void H_I2C_Start(I2C_TypeDef* I2Cx)
{
    // 等待I2C总线空闲
    H_I2C_WaitEvent(I2Cx, I2C_FLAG_BUSY);
    
    // 产生起始信号
    I2C_GenerateSTART(I2Cx, ENABLE);
    
    // 等待起始信号发送完成
    H_I2C_WaitEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT);
}

/**
  * @brief  产生I2C停止信号
  * @param  I2Cx: 要操作的I2C外设
  * @retval 无
  */
void H_I2C_Stop(I2C_TypeDef* I2Cx)
{
    // 产生停止信号
    I2C_GenerateSTOP(I2Cx, ENABLE);
}

/**
 *  @brief  发送设备地址
 * @param  I2Cx: 要操作的I2C外设
 * @param  DevAddress: 设备地址
 * @param  Direction: 传输方向，I2C_Direction_Transmitter: 发送 I2C_Direction_Receiver: 接收
 * @retval 无
 */
void H_I2C_SendDevAddress(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint8_t Direction)
{
    I2C_Send7bitAddress(I2Cx, DevAddress, Direction);
    H_I2C_WaitEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
}

/**
  * @brief  发送一个字节
  * @param  I2Cx: 要操作的I2C外设
  * @param  Data: 要发送的数据
  * @retval 无
  */
void H_I2C_SendByte(I2C_TypeDef* I2Cx, uint8_t Data)
{
    
    // 发送数据
    I2C_SendData(I2Cx, Data);
    
    // 等待数据发送完成
    H_I2C_WaitEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
}

/**
  * @brief  接收一个字节
  * @param  I2Cx: 要操作的I2C外设
  * @retval 接收到的数据
  */
uint8_t H_I2C_ReceiveByte(I2C_TypeDef* I2Cx)
{
    // 等待数据接收完成
    H_I2C_WaitEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED);
    
    // 读取接收到的数据
    return I2C_ReceiveData(I2Cx);
}

/**
  * @brief  发送应答
  * @param  I2Cx: 要操作的I2C外设
  * @param  AckBit: 应答位，0表示应答，1表示非应答
  * @retval 无
  */
void H_I2C_SendAck(I2C_TypeDef* I2Cx, uint8_t AckBit)
{
    if (AckBit == 0)
    {
        // 发送应答
        I2C_AcknowledgeConfig(I2Cx, ENABLE);
    }
    else
    {
        // 发送非应答
        I2C_AcknowledgeConfig(I2Cx, DISABLE);
    }
}

/**
  * @brief  接收应答
  * @param  I2Cx: 要操作的I2C外设
  * @retval 接收到的应答位，0表示应答，1表示非应答
  */
uint8_t H_I2C_ReceiveAck(I2C_TypeDef* I2Cx)
{
    // 硬件I2C自动处理应答，此函数仅为接口兼容
    // 实际上STM32硬件I2C会自动处理应答，不需要手动接收应答
    return 0;
}

/**
  * @brief  检查指定设备是否就绪
  * @param  I2Cx: 要操作的I2C外设
  * @param  DevAddress: 设备地址
  * @param  Trials: 尝试次数
  * @retval 设备状态，0表示就绪，1表示未就绪
  */
uint8_t H_I2C_CheckDevice(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint8_t Trials)
{
    uint8_t i;
    
    for (i = 0; i < Trials; i++)
    {
        // 产生起始信号
        I2C_GenerateSTART(I2Cx, ENABLE);
        
        // 等待起始信号发送完成
        H_I2C_WaitEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT);
        
        // 发送设备地址+写命令
        I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmitter);
        
        // 等待地址发送完成
        if(H_I2C_WaitEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
        {
            // 产生停止信号
            H_I2C_Stop(I2Cx);

            return 0;  // 设备就绪
        }
    }
    
    return 1;  // 设备未就绪
}

/**
  * @brief  写寄存器
  * @param  I2Cx: 要操作的I2C外设
  * @param  DevAddress: 设备地址
  * @param  RegAddress: 寄存器地址
  * @param  Data: 要写入的数据
  * @retval 无
  */
void H_I2C_WriteReg(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint8_t RegAddress, uint8_t Data)
{
    // 产生起始信号
    H_I2C_Start(I2Cx);
    
    // 发送设备地址+写命令
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmitter);
    H_I2C_WaitEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    
    // 发送寄存器地址
    H_I2C_SendByte(I2Cx, RegAddress);
    
    // 发送数据
    H_I2C_SendByte(I2Cx, Data);
    
    // 产生停止信号
    H_I2C_Stop(I2Cx);
}

/**
  * @brief  读寄存器
  * @param  I2Cx: 要操作的I2C外设
  * @param  DevAddress: 设备地址
  * @param  RegAddress: 寄存器地址
  * @retval 读取到的数据
  */
uint8_t H_I2C_ReadReg(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint8_t RegAddress)
{
    uint8_t data;
    
    // 产生起始信号
    H_I2C_Start(I2Cx);
    
    // 发送设备地址+写命令
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    
    // 发送寄存器地址
    H_I2C_SendByte(I2Cx, RegAddress);
    
    // 产生重复起始信号
    H_I2C_Start(I2Cx);
    
    // 发送设备地址+读命令
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Receiver);
    uint16_t timeout = 10000;  // 重置超时计数器
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
    {
        timeout--;
        if (timeout == 0)
        {
            return;  // 超时退出
        }
    }
    
    // 配置为接收一个字节后发送非应答
    I2C_AcknowledgeConfig(I2Cx, DISABLE);
    
    // 接收数据
    data = H_I2C_ReceiveByte(I2Cx);
    
    // 产生停止信号
    H_I2C_Stop(I2Cx);
    
    // 重新使能应答
    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    
    return data;
}

/**
  * @brief  连续写多个字节
  * @param  I2Cx: 要操作的I2C外设
  * @param  DevAddress: 设备地址
  * @param  RegAddress: 寄存器起始地址
  * @param  pData: 数据缓冲区指针
  * @param  Length: 数据长度
  * @retval 无
  */
void H_I2C_WriteMulti(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint8_t RegAddress, uint8_t* pData, uint16_t Length)
{
    uint16_t i;
    
    // 产生起始信号
    H_I2C_Start(I2Cx);
    
    // 发送设备地址+写命令
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmitter);
    H_I2C_WaitEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    
    // 发送寄存器地址
    H_I2C_SendByte(I2Cx, RegAddress);
    
    // 连续发送数据
    for (i = 0; i < Length; i++)
    {
        H_I2C_SendByte(I2Cx, pData[i]);
    }
    
    // 产生停止信号
    H_I2C_Stop(I2Cx);
}

/**
  * @brief  连续读多个字节
  * @param  I2Cx: 要操作的I2C外设
  * @param  DevAddress: 设备地址
  * @param  RegAddress: 寄存器起始地址
  * @param  pData: 数据缓冲区指针
  * @param  Length: 数据长度
  * @retval 无
  */
void H_I2C_ReadMulti(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint8_t RegAddress, uint8_t* pData, uint16_t Length)
{
    uint16_t i;
    
    // 产生起始信号
    H_I2C_Start(I2Cx);
    
    // 发送设备地址+写命令
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    
    // 发送寄存器地址
    H_I2C_SendByte(I2Cx, RegAddress);
    
    // 产生重复起始信号
    H_I2C_Start(I2Cx);
    
    // 发送设备地址+读命令
    I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Receiver);
    uint16_t timeout = 10000;  // 重置超时计数器
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
    {
        timeout--;
        if (timeout == 0)
        {
            return;  // 超时退出
        }
    }
    
    // 连续接收数据
    for (i = 0; i < Length; i++)
    {
        if (i == Length - 1)
        {
            // 最后一个字节发送非应答
            I2C_AcknowledgeConfig(I2Cx, DISABLE);
        }
        
        // 接收数据
        pData[i] = H_I2C_ReceiveByte(I2Cx);
    }
    
    // 产生停止信号
    H_I2C_Stop(I2Cx);
    
    // 重新使能应答
    I2C_AcknowledgeConfig(I2Cx, ENABLE);
}

/**
/**
  * @brief  等待指定事件发生
  * @param  同I2C_CheckEvent
  * @return 1 成功 0 失败
  */
uint8_t H_I2C_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
    uint32_t Timeout;
    Timeout = 10000;                                    //给定超时计数时间
    while (I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS) //循环等待指定事件
    {
        Timeout--;                                      //等待时，计数值自减
        if (Timeout == 0)                              //自减到0后，等待超时
        {
            /*超时的错误处理代码，可以添加到此处*/
            return 0;                                   //超时返回0表示失败
        }
    }
    return 1;                                          //成功返回1
}
